<?php
/**
 * Mô tả:
 * 
 * @version : 1.0
 * @since June-2008
 * @deprecated  Lớp mở rộng của CRecord
 * @package : lib/cache
 * @todo:  Lớp Resource của Item. Như Image, Thumbnail , media, ....
*/
/**
 * Định nghĩa một số hàm dùng chung cho lớp CCategory
 *
 */

class CCategory extends CRecord 
{
	const ACTIVE_STATUS = 1;
	const INACTIVE_STATUS = 0;
	const DELETED_STATUS = 2;
	
	protected $table;
	/**
	 * Hàm __construct khởi tạo một bản ghi các bảng category
	 *
	 * @param  $table
	 * @param  $record
	 */
    function __construct($table, $record = array())
    {
    	if(is_string($table))
    	{
    		$this->table = CTable($table);
    	}
    	else 
    	{
    		$this->table = $table;
    	}
   		parent::__construct($record);
    }
    /**
     * Phương thức chèn một Category mới vào một category cha
     *
     * @param Thông tin của category mới $data
     * @param id của category cha $parent_id
     */
    function insert($data, $parent_id)
    {	$parent_structure_id = $this -> structure_id($parent_id);
    	$data['structure_id'] = $this->available_child($parent_structure_id);
    	if ($data['structure_id']<CStructureID::ID_ROOT) 
    	{
    		$data['structure_id'] = CStructureID::ID_ROOT;
    	}
    	$this->table->original_record = false;
    	$this->table->save($data);   	
    	
    }
    /**
     * Phương thức cập nhật thông tin mới cho một category, bao gồm cả việc đổi category cha của nó
     *
     * @param Id của category cần thay đổi, ta cũng có thể truyền vào một mảng là dữ liệu mới cần cập nhật của nó $id
     * @param Id của category cha, nếu không đưa vào thì sẽ lấy luôn id của category hiện tại $parent_id
     */
      
	static function category_json($table)
	{
		$categories = $table->select_all(false, array('order_by'=>'structure_id', 'fields'=>'id,name,structure_id'));
		foreach($categories as &$category)
		{
			$category['level'] = CStructureID($category['structure_id'])->level();
		}
		return CString($categories)->json();
	}
	/**
	 * Hàm si_update: Cập nhật thông tin mới cho một category (kể cả đối với category cha của nó).
	 *
	 * @param  $id là id của category
	 * @param  $parent_id là mã id của category cha
	 */
    function si_update($id, $parent_id = false)    
    {	
    	if(is_array($id))
    	{
    		$data = $id;
    		$id = $id['id'];
    	}
    	else 
    	{
    		$data = $this->table-> select($id);
    	}
    	$structure_id = $this->structure_id($data);
    	if (isset($parent_id ))
    	{
    		$parent_structure_id = $this -> structure_id($parent_id);
    	}
    	else 
    	{
    		$parent_structure_id = $structure_id;
    	}   	 
    	   	
    	$new_si = $this->available_child($parent_structure_id);
    	$this->structure_id_change($structure_id,$new_si);
    	//Cập nhật lại Id của category hiện tại và các con của nó
    	/*$data=$this->table->select_all( CStructureID($parent_structure_id)->child_condition()); 
    	foreach ($data as $row)
    	{	$row['status'] = CRecord($this->table->select($id))->status ;    		
    		$this->table->select($row['id']);
    		$this->table-> save($row);
    	}*/
    }
    /**
     * Hàm delete: xoá tạm thời một cái category
     *
     * @param $id là mã id của category cần xoá
     */
    function delete($id)    
    {	$parent_structure_id =$this -> structure_id($id);    		
    	$data=$this->table->select_all( CStructureID($parent_structure_id)->child_condition()); 
    	foreach ($data as $row)
    	{	$row['status'] = CCategory::DELETED_STATUS   ;
    		$this->table->select($row['id']);
    		$this->table-> save($row);
    	}
    }
    /**
     * Hàm permanent_delete: xoá vĩnh viễn một cái category
     *
     * @param biến $id là mã id của category cần xoá
     */
    function permanent_delete($id)    
    {	$parent_structure_id =$this -> structure_id($id);    		
    	$data=$this -> table-> select_all( CStructureID($parent_structure_id)->child_condition()); 
    	foreach ($data as $row)
    	{	
    		$this -> table-> delete($row['id']);   		   		
    	}
    }
    /**
     * Hàm move_up: Đẩy category lên trên một cái category khác.
     *
     * @param $id là id(mã) của category cần đẩy lên
     */
    function move_up($id)
    {
    	$structure_id = $this->structure_id($id);
    	$above_structure_id = CStructureID($structure_id)->above_structure_id();
    	$parent_structure_id = CStructureID($structure_id)->parent();
    	$temp = $this->available_child($parent_structure_id);
    	$this->structure_id_change($structure_id,$temp);
    	$this->structure_id_change($above_structure_id,$structure_id);
    	$this->structure_id_change($temp,$above_structure_id);
    }
    /**
     * Hàm move_down: để dịch chuyển một category xuống dưới một cái category khác
     *
     * @param id của category cần đẩy xuống $id
     */
    function move_down($id)
    {
    	$structure_id = $this->structure_id($id);
    	$under_structure_id = CStructureID($structure_id)->under_structure_id();
    	$parent_structure_id = CStructureID($structure_id)->parent();
    	$temp = $this->available_child($parent_structure_id);
    	$this->structure_id_change($structure_id,$temp);
    	$this->structure_id_change($under_structure_id,$structure_id);
    	$this->structure_id_change($temp,$under_structure_id);
    	
    }
    /**
     * Hàm move_top: đẩy category lên trên đỉnh
     *
     * @param id của category muốn đẩy $id
     */
    function move_top($id)
    {    
    	$structure_id = $this->structure_id($id);    	
    	$parent_structure_id = CStructureID($structure_id)->parent();    	
    	$temp_si = $this->available_child($parent_structure_id);
    	$new_si = CStructureID($parent_structure_id)->first_child();    	
    	$this->structure_id_change($structure_id,$temp_si);
    	$data=$this -> table-> select_all( CStructureID($structure_id)->above_condition(),array('order by' => 'structure_id DESC' )); 
    	foreach ($data as $row)
    	{	$update_si = CStructureID($row['structure_id'])->next_structure_id();
    		$this->structure_id_change($row['structure_id'],$update_si);   		
    	}
    	$this->structure_id_change($temp_si,$new_si);
    }
	 /**
	  * Hàm đẩy một category xuống dưới cùng của danh sách các category
	  *
	  * @param id của category muốn đẩy $id
	  */
    function move_bottom($id)
    {	$structure_id = $this->structure_id($id);    	   	
    	$parent_structure_id = CStructureID($structure_id)->parent();
    	$new_si = $this->available_child($parent_structure_id);
    	$this->structure_id_change($structure_id,$new_si);
    	
    }
/**
 * Hàm đổi structure_id của một bản ghi sang một structure_id mới đồng thời đổi structure_id của tất cả các bản ghi là con của nó
 *
 * @param structure_id cũ $structure_id
 * @param structure_id mới $new_structure_id
 */
function structure_id_change($structure_id, $new_structure_id)
{
	if($structure_id != $new_structure_id)
	{
		// Tính độ dịch chuyển theo cấp
		$old_level=CStructureID($structure_id) -> level();
		$new_level=CStructureID($new_structure_id) -> level();
		$mul = pow(CStructureID::ID_BASE, $new_level-$old_level);
		$data=$this -> table-> select_all( CStructureID($structure_id)->child_condition());
		foreach($data as $row)
    	{	
    		$original_row = $row;
    		$row['structure_id'] = floor(($row['structure_id']-$structure_id) / $mul + $new_structure_id);
    		$this -> table->original_record = CRecord($original_row);
    		$this -> table->save($row);
    	}		
	}
}
/**
 * Hàm lấy ra structure_id của một bản ghi có id cho trước
 *
 * @param Id biết trước $id
 * @return structure_id của một bản ghi có id được chỉ ra
 */
    function structure_id($id = false)
    {	
    	if(!$id)
    	{
    		return $this->structure_id;
    	}
    	if(is_array($id) and isset($id['structure_id']))
    	{
    		return $id['structure_id'];
    	}
    	else 
    	{
    		return CRecord($this->table->select($id))->structure_id;
    	}
    }
 /**
  * Hàm tính Structure_id khả dụng làm con của một bản ghi có structure_id cho trước
  *
  * @param id của bản ghi cha $parent_structure_id
  * @return Structure_id khả dụng để làm con
  */
    function available_child($parent_structure_id)
	{		  		
    	$data = $this -> table -> select_all(  CStructureID($parent_structure_id)->child_condition(true),array('order by' => 'structure_id '));
    	$max=$available=CStructureID($parent_structure_id)->first_child();
    	if (!empty($data))
    	{     	
		  foreach ($data as $row)
		   {	
		    	if (($row['structure_id'] > $max) and (CStructureID($row['structure_id'])->level() == CStructureID($max)->level()))
		    	{
		    		$max=$row['structure_id'];    			  		   		
		    	}      			
		   } 
		   if ($max >=$available)
		   {
		   		$available=CStructureID($max)->next_structure_id();    	   
		   } 
    	}   	  	
    	return $available; 
	}
	static function get_list($fn)
	{
		$cats = CTable('cats/cat/cats/cat')->change_store(new CDataXmlStore($fn))->select_all();
		$items = array();
		CCategory::get_list_cats($cats, $items, 1);
		return $items;
	}
	static function get_list_cats($cats, &$items, $level)
	{
		foreach($cats as &$cat)
		{
			$items[] = $cat+array(
				'level' => $level,
				'indent' => ($level>1)?str_repeat('   ',($level-1)):''
			);
			if(isset($cat['cats']) and is_array($cat['cats']) and $cat['cats'])
			{
				CCategory::get_list_cats($cat['cats'], $items, $level + 1);
			}
		}
	}
	static function ul_li(&$items, $child_tag = 'cats')
	{
		$code = '<ul>';
		foreach($items as $item)
		{
			$code .= '<li>'.$item['code'];
			if(isset($item[$child_tag]) and $item[$child_tag])
			{
				$code .= CCategory::ul_li($item[$child_tag], $child_tag);
			}
			$code .= '</li>';
		}
		$code .= '</ul>';
		return $code;
	}
	static function options($items, $options = array())
	{
		return CCategory::_options($items, array_merge(array('tag'=>'cats'), $options), 0);
	}
	static function _options($items, $options, $level)
	{
		$code = '';
		foreach($items as $item)
		{
			$code .= '<option value="'.$item['id'].'"'.($level?' style="padding-left:'.($level*20).'px"':'').((isset($options['value']) and $options['value'] == $item['id'])?' selected="selected"':'').'>'.$item['name'].'</option>';
			if(isset($item[$options['tag']]) and $item[$options['tag']])
			{
				$code .= CCategory::_options($item[$options['tag']], $options, $level+1);
			}
		}
		return $code;
	}
	static function parse(&$items, $func, $child_tag = 'cats')
	{
		foreach($items as &$item)
		{
			$func($item);
			if(isset($item[$child_tag]) and $item[$child_tag])
			{
				CCategory::parse($item[$child_tag], $func, $child_tag);
			}
		}
	}
}//end Class

function CCategory($table=false)
{
	return new CCategory($table,false);
}


?>